import { Injectable, Logger } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
import { AxiosResponse, AxiosRequestConfig } from 'axios';
import { TokenManager } from '../interfaces/api-adapter.interface';
import { ProxyConfigService } from '../config/proxy.config';
import { CopilotRequestLoggerService } from './copilot-request-logger.service';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { HttpProxyAgent } from 'http-proxy-agent';

export interface CopilotTokenInfo {
  token: string;
  expiresAt: number;
  isValid: boolean;
}

@Injectable()
export class TokenManagerService implements TokenManager {
  private readonly logger = new Logger(TokenManagerService.name);
  private currentToken: string | null = null;
  private tokenExpiresAt: number = 0;
  private githubToken: string = '';
  private readonly TOKEN_REFRESH_BUFFER = 300; // 5分钟缓冲时间

  constructor(
    private readonly httpService: HttpService,
    private readonly proxyConfigService: ProxyConfigService,
    private readonly copilotLogger: CopilotRequestLoggerService
  ) {
    // 将从数据库动态加载GitHub token
  }

  /**
   * 从数据库加载GitHub token
   */
  private async loadGithubTokenFromDatabase(): Promise<void> {
    const requestId = this.copilotLogger.createRequestContext();
    
    try {
      const copilotConfig = await this.proxyConfigService.getCopilotConfig();
      this.githubToken = copilotConfig.githubToken || '';
      
      if (this.githubToken) {
        // 简化的控制台日志
        this.logger.log('GitHub token loaded from database');
        
        // 详细的文件日志
        await this.copilotLogger.logTokenRefresh(
          requestId,
          'TokenManagerService',
          'GitHub token loaded from database successfully',
          {
            tokenLength: this.githubToken.length,
            tokenPrefix: this.githubToken.substring(0, 10) + '...',
            source: 'database'
          }
        );
      } else {
        this.logger.warn('No GitHub token found in database');
        
        await this.copilotLogger.logCopilotRequestLegacyFormat({
          requestId,
          phase: 'token_refresh',
          service: 'TokenManagerService',
          level: 'warn',
          message: 'No GitHub token found in database configuration',
          data: { source: 'database', hasToken: false }
        });
      }
    } catch (error) {
      this.logger.error(`Failed to load GitHub token: ${error.message}`);
      this.githubToken = '';
      
      await this.copilotLogger.logErrorLegacy(
        requestId,
        'TokenManagerService',
        'Failed to load GitHub token from database',
        error,
        { source: 'database' }
      );
    }
  }

  /**
   * 设置GitHub原始token
   */
  setGithubToken(token: string): void {
    const requestId = this.copilotLogger.createRequestContext();
    
    this.githubToken = token;
    
    // 简化的控制台日志
    this.logger.log('GitHub token updated manually');
    
    // 详细的文件日志
    this.copilotLogger.logTokenRefresh(
      requestId,
      'TokenManagerService',
      'GitHub token updated manually',
      {
        tokenLength: this.githubToken.length,
        tokenPrefix: this.githubToken.substring(0, 10) + '...',
        source: 'manual_update'
      }
    );
  }

  /**
   * 重新从数据库加载GitHub token
   */
  async reloadGithubToken(): Promise<void> {
    const requestId = this.copilotLogger.createRequestContext();
    
    // 简化的控制台日志
    this.logger.log('Reloading GitHub token');
    
    // 详细的文件日志
    await this.copilotLogger.logTokenRefresh(
      requestId,
      'TokenManagerService',
      'Starting GitHub token reload from database',
      { action: 'reload_start' }
    );
    
    await this.loadGithubTokenFromDatabase();
  }

  /**
   * 获取有效的Copilot token
   */
  async getValidToken(): Promise<string> {
    const requestId = this.copilotLogger.createRequestContext();
    
    // 如果还没有GitHub token，先从数据库加载
    if (!this.githubToken) {
      this.logger.log('Loading GitHub token from database');
      
      await this.copilotLogger.logTokenRefresh(
        requestId,
        'TokenManagerService',
        'GitHub token not loaded, loading from database',
        { action: 'auto_load', hasGithubToken: false }
      );
      
      await this.loadGithubTokenFromDatabase();
    }
    
    if (this.isTokenValid()) {
      this.logger.debug('Using cached Copilot token');
      
      await this.copilotLogger.logCopilotRequestLegacyFormat({
        requestId,
        phase: 'token_refresh',
        service: 'TokenManagerService',
        level: 'debug',
        message: 'Using cached valid Copilot token',
        data: {
          action: 'use_cached',
          tokenExpiresAt: this.tokenExpiresAt,
          expiresInMinutes: Math.floor((this.tokenExpiresAt - Date.now() / 1000) / 60)
        }
      });
      
      return this.currentToken!;
    }

    this.logger.log('Refreshing expired Copilot token');
    
    await this.copilotLogger.logTokenRefresh(
      requestId,
      'TokenManagerService',
      'Token expired or missing, starting refresh process',
      {
        action: 'refresh_needed',
        hasCurrentToken: !!this.currentToken,
        tokenExpiresAt: this.tokenExpiresAt,
        currentTime: Math.floor(Date.now() / 1000)
      }
    );
    
    await this.refreshToken(requestId);
    return this.currentToken!;
  }

  /**
   * 检查token是否有效
   */
  isTokenValid(): boolean {
    if (!this.currentToken) {
      return false;
    }

    const now = Math.floor(Date.now() / 1000);
    const isValid = now < (this.tokenExpiresAt - this.TOKEN_REFRESH_BUFFER);
    
    this.logger.debug('Token validation', {
      hasToken: !!this.currentToken,
      expiresAt: this.tokenExpiresAt,
      currentTime: now,
      bufferTime: this.TOKEN_REFRESH_BUFFER,
      isValid
    });

    return isValid;
  }

  /**
   * 创建代理配置用于GitHub API请求
   */
  private createProxyConfig(copilotConfig: any): any {
    if (!copilotConfig.proxy?.enabled || !copilotConfig.proxy?.url) {
      return undefined;
    }

    try {
      const proxyUrl = new URL(copilotConfig.proxy.url);
      
      // 如果有用户名和密码，添加到 URL 中
      if (copilotConfig.proxy.username && copilotConfig.proxy.password) {
        proxyUrl.username = copilotConfig.proxy.username;
        proxyUrl.password = copilotConfig.proxy.password;
      }

      // GitHub API 使用 HTTPS，所以使用 HttpsProxyAgent
      return new HttpsProxyAgent(proxyUrl.toString());
    } catch (error) {
      this.logger.warn(`Failed to create proxy config for GitHub API: ${error.message}`);
      return undefined;
    }
  }

  /**
   * 刷新Copilot token
   */
  async refreshToken(requestId?: string): Promise<void> {
    const refreshStartTime = Date.now();
    const tokenRequestId = requestId || this.copilotLogger.createRequestContext();
    
    // 重新从数据库加载GitHub token，确保使用最新的配置
    await this.reloadGithubToken();
    
    if (!this.githubToken) {
      const error = new Error('GitHub token not set. Please configure GitHub token in database.');
      
      await this.copilotLogger.logErrorLegacy(
        tokenRequestId,
        'TokenManagerService',
        'GitHub token not configured for token refresh',
        error,
        { action: 'refresh_failed', reason: 'no_github_token' }
      );
      
      throw error;
    }

    try {
      const copilotConfig = await this.proxyConfigService.getCopilotConfig();
      const proxyAgent = this.createProxyConfig(copilotConfig);
      
      const requestUrl = 'https://api.github.com/copilot_internal/v2/token';
      const requestHeaders = {
        'authorization': `Bearer ${this.githubToken}`,
        'copilot-language-server-version': '1.348.0',
        'editor-plugin-version': 'copilot-intellij/1.5.52-241',
        'editor-version': 'JetBrains-IU/241.14494.240',
        'user-agent': 'GithubCopilot/1.348.0',
        'x-github-api-version': '2024-12-15'
      };

      const requestConfig: AxiosRequestConfig = {
        headers: requestHeaders,
        timeout: 10000
      };

      // 如果有代理配置，添加到请求中
      if (proxyAgent) {
        requestConfig.httpsAgent = proxyAgent;
        this.logger.debug('Using proxy for GitHub API request', {
          proxyUrl: copilotConfig.proxy?.url,
          hasAuth: !!(copilotConfig.proxy?.username && copilotConfig.proxy?.password)
        });
      }

      // 简化的控制台日志
      this.logger.log('Requesting new Copilot token from GitHub API');
      
      // 详细的文件日志
      await this.copilotLogger.logCopilotRequestLegacyFormat({
        requestId: tokenRequestId,
        phase: 'token_refresh',
        service: 'TokenManagerService',
        level: 'info',
        message: 'Sending request to GitHub API for new Copilot token',
        data: {
          url: requestUrl,
          method: 'GET',
          githubTokenLength: this.githubToken.length,
          githubTokenPrefix: this.githubToken.substring(0, 10) + '...',
          proxyEnabled: !!proxyAgent,
          requestHeaders: Object.keys(requestHeaders)
        }
      });
      
      const response: AxiosResponse<any> = await firstValueFrom(
        this.httpService.get(requestUrl, requestConfig)
      );

      // 简化的控制台日志
      this.logger.log(`GitHub API response: ${response.status}`);
      
      // 详细的文件日志
      await this.copilotLogger.logCopilotRequestLegacyFormat({
        requestId: tokenRequestId,
        phase: 'token_refresh',
        service: 'TokenManagerService',
        level: 'info',
        message: 'GitHub API response received',
        data: {
          status: response.status,
          statusText: response.statusText,
          responseHeaders: {
            'content-type': response.headers['content-type'],
            'x-ratelimit-limit': response.headers['x-ratelimit-limit'],
            'x-ratelimit-remaining': response.headers['x-ratelimit-remaining'],
            'x-ratelimit-reset': response.headers['x-ratelimit-reset']
          },
          responseData: {
            hasToken: !!response.data?.token,
            tokenLength: response.data?.token?.length || 0,
            tokenPrefix: response.data?.token?.substring(0, 50) || 'N/A',
            dataKeys: Object.keys(response.data || {})
          }
        }
      });

      if (response.status !== 200) {
        throw new Error(`GitHub API returned status ${response.status}: ${response.statusText}`);
      }

      // 解析响应获取新的token
      const tokenData = response.data;
      if (!tokenData || !tokenData.token) {
        const error = new Error('Invalid token response from GitHub API');
        
        this.logger.error('Invalid token response structure');
        
        await this.copilotLogger.logErrorLegacy(
          tokenRequestId,
          'TokenManagerService',
          'Invalid token response structure from GitHub API',
          error,
          {
            hasData: !!tokenData,
            dataKeys: tokenData ? Object.keys(tokenData) : [],
            tokenField: tokenData?.token,
            responseStatus: response.status
          }
        );
        
        throw error;
      }

      this.currentToken = tokenData.token;
      this.tokenExpiresAt = this.parseTokenExpiry(tokenData.token);

      const refreshDuration = Date.now() - refreshStartTime;
      
      // 简化的控制台日志
      this.logger.log(`Token refreshed successfully (${refreshDuration}ms)`);
      
      // 详细的文件日志
      await this.copilotLogger.logTokenRefresh(
        tokenRequestId,
        'TokenManagerService',
        'Copilot token refreshed successfully',
        {
          tokenLength: this.currentToken.length,
          tokenPrefix: this.currentToken.substring(0, 50) + '...',
          expiresAt: this.tokenExpiresAt,
          expiresAtDate: new Date(this.tokenExpiresAt * 1000).toISOString(),
          expiresInMinutes: Math.floor((this.tokenExpiresAt - Date.now() / 1000) / 60),
          refreshSuccess: true
        },
        refreshDuration
      );

    } catch (error) {
      const refreshDuration = Date.now() - refreshStartTime;
      
      // 简化的控制台错误日志
      this.logger.error(`Failed to refresh Copilot token: ${error.message}`);
      
      // 详细的错误文件日志
      await this.copilotLogger.logErrorLegacy(
        tokenRequestId,
        'TokenManagerService',
        'Failed to refresh Copilot token',
        error,
        {
          errorType: error.constructor.name,
          githubTokenLength: this.githubToken.length,
          requestUrl: 'https://api.github.com/copilot_internal/v2/token',
          httpStatus: error.response?.status,
          httpStatusText: error.response?.statusText,
          responseData: error.response?.data,
          responseHeaders: error.response?.headers,
          refreshDuration
        }
      );
      
      throw new Error(`Token refresh failed: ${error.message}`);
    }
  }

  /**
   * 从token字符串中解析过期时间
   */
  private parseTokenExpiry(token: string): number {
    try {
      // Token格式: tid=...;exp=1754193177;sku=...
      const expMatch = token.match(/exp=(\d+)/);
      if (!expMatch) {
        throw new Error('Token does not contain expiry information');
      }

      const expiryTimestamp = parseInt(expMatch[1], 10);
      if (isNaN(expiryTimestamp)) {
        throw new Error('Invalid expiry timestamp in token');
      }

      return expiryTimestamp;
    } catch (error) {
      this.logger.error('Failed to parse token expiry', { token: token.substring(0, 50) + '...', error: error.message });
      throw error;
    }
  }

  /**
   * 获取token信息
   */
  getTokenInfo(): CopilotTokenInfo {
    return {
      token: this.currentToken || '',
      expiresAt: this.tokenExpiresAt,
      isValid: this.isTokenValid()
    };
  }

  /**
   * 清除缓存的token（用于测试或重置）
   */
  clearToken(): void {
    const requestId = this.copilotLogger.createRequestContext();
    
    const hadToken = !!this.currentToken;
    const oldExpiresAt = this.tokenExpiresAt;
    
    this.currentToken = null;
    this.tokenExpiresAt = 0;
    
    // 简化的控制台日志
    this.logger.log('Token cache cleared');
    
    // 详细的文件日志
    this.copilotLogger.logTokenRefresh(
      requestId,
      'TokenManagerService',
      'Token cache cleared manually',
      {
        action: 'clear_cache',
        hadToken,
        oldExpiresAt,
        clearedAt: Date.now()
      }
    );
  }

  /**
   * 检查服务健康状态
   */
  async checkHealth(): Promise<{ status: string; tokenValid: boolean; expiresIn?: number }> {
    const tokenValid = this.isTokenValid();
    const result: any = {
      status: this.githubToken ? 'configured' : 'not_configured',
      tokenValid,
      hasGithubToken: !!this.githubToken,
      hasCopilotToken: !!this.currentToken
    };

    if (tokenValid && this.tokenExpiresAt > 0) {
      const now = Math.floor(Date.now() / 1000);
      result.expiresIn = Math.max(0, this.tokenExpiresAt - now);
    }

    return result;
  }
}